/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package etherblocks.game.entitysystem;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 *
 * @author Carl
 */
public class EntityMap{

    public EntityMap(){
        
    }
    private ConcurrentHashMap<Integer, ConcurrentHashMap<Class, Object>> components = new ConcurrentHashMap<Integer, ConcurrentHashMap<Class, Object>>();
    private int nextEntityID;
    private ArrayList<EntityMapListener> listeners = new ArrayList<EntityMapListener>();
    
    public Entity createNewEntity(int id){
        if(id < nextEntityID){
            throw new IllegalArgumentException();
        }
        nextEntityID = id;
        return createNewEntity();
    }
    
    public Entity createNewEntity(){
        Entity entity = new Entity(this, nextEntityID);
        nextEntityID++;
        for(int i=0;i<listeners.size();i++){
            listeners.get(i).onEntityAdded(entity.getID());
        }
        return entity;
    }
    
    public <T> T getComponent(int entityID, Class<T> componentClass){
        ConcurrentHashMap<Class, Object> entityComponents = components.get(entityID);
        if(entityComponents != null){
            return (T) entityComponents.get(componentClass);
        }
        return null;
    }
    
    public void setComponent(int entityID, Object component){
        ConcurrentHashMap<Class, Object> entityComponents = components.get(entityID);
        if(entityComponents == null){
            entityComponents = new ConcurrentHashMap<Class, Object>();
            components.put(entityID, entityComponents);
        }
        entityComponents.put(component.getClass(), component);
        for(int i=0;i<listeners.size();i++){
            listeners.get(i).onComponentAdded(entityID, component);
        }
    }
    
    public void clearAllComponents(int entityID){
        ConcurrentHashMap<Class, Object> entityComponents = components.get(entityID);
        if(entityComponents != null){
            Iterator<Class> componentClasses = entityComponents.keySet().iterator();
            while(componentClasses.hasNext()){
                clearComponent(entityID, componentClasses.next());
            }
        }
    }
    
    public void clearComponent(int entityID, Class componentClass){
        ConcurrentHashMap<Class, Object> entityComponents = components.get(entityID);
        if(entityComponents != null){
            Object removedComponent = entityComponents.remove(componentClass);
            for(int i=0;i<listeners.size();i++){
                listeners.get(i).onComponentRemoved(entityID, removedComponent);
            }
        }
    }
    
    public List<Entity> getEntities(Class... requiredComponents){
        List<Entity> entities = new LinkedList<Entity>();
        Iterator<Integer> entitiesIDIterator = components.keySet().iterator();
        while(entitiesIDIterator.hasNext()){
            int entityID = entitiesIDIterator.next();
            if(filterEntity(entityID, requiredComponents)){
                entities.add(new Entity(this, entityID));
            }
        }
        return entities;
    }
    
    public Entity getFilteredEntity(int entityID, Class... requiredComponents){
        if(filterEntity(entityID, requiredComponents)){
            return new Entity(this, entityID);
        }
        return null;
    }
    
    public boolean filterEntity(int entityID, Class... requiredComponents){
        ConcurrentHashMap<Class, Object> entityComponents = components.get(entityID);
        boolean containsRequiredComponents = true;
        for(int i=0;i<requiredComponents.length;i++){
            if(!entityComponents.containsKey(requiredComponents[i])){
                containsRequiredComponents = false;
                break;
            }
        }
        return containsRequiredComponents;
    }
    
    public void removeEntity(int entityID){
        components.remove(entityID);
        for(int i=0;i<listeners.size();i++){
            listeners.get(i).onEntityRemoved(entityID);
        }
    }
    
    public void addListener(EntityMapListener listener){
        listeners.add(listener);
    }
    
    public void removeListener(EntityMapListener listener){
        listeners.remove(listener);
    }

    public ConcurrentHashMap<Integer, ConcurrentHashMap<Class, Object>> getComponents(){
        return components;
    }
}
